package client

import (
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"sync"
)

// upgrade 即 HTTP 连接升级器
// 用于将 HTTP 连接升级为 Websocket
var upgrade = &websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

// SessionPool
// 这是一个 Session 池，也是客户端池
// 它管理着服务端的客户端列表
// 创建、连接替换、销毁等
type SessionPool struct {
	sync.RWMutex
	clientList sync.Map
	New        func(c *gin.Context, playerId string) Client
}

// Get
// 请求获取一个新的客户端
func (p *SessionPool) Get(c *gin.Context, playerId string) Client {
	if p.New == nil {
		return nil
	}

	//	升级 HTTP 连接至 Websocket 连接
	conn, err := upgrade.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		return nil
	}

	//	当互斥条件打开时，当同样的 PlayerId 连接进来时，服务端会关闭旧连接
	//	同时替换新的连接并释放旧连接，但要求Session中的数据状态保持原样
	if v, ok := p.clientList.Load(playerId); ok {
		replacer := v.(Connection)

		//	开始替换连接
		if err := replacer.Replace(conn); err != nil {
			log.Printf("[SESS_POOL] %s\n", err.Error())
			return nil
		}

		//	如果替换成功则返回当前客户端
		return v.(Client)
	}

	//	当一个新的连接进来时，创建一个新的Session并创建连接
	client := p.New(c, playerId)
	client.SetConnection(conn)

	//	把连接保存在客户端池中
	p.clientList.Store(playerId, client)

	return client
}

// Destroy
// 销毁 Session
func (p *SessionPool) Destroy(playerId string) {
	if v, ok := p.clientList.Load(playerId); ok {
		client := v.(Client)

		//	删除客户端客户端池的列表
		//	当客户端不再被引用时，释放客户端池
		if client.QuoteTotal() <= 0 {
			p.clientList.Delete(playerId)
		}
	}
}
